package org.javaboy.ai.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.javaboy.ai.domain.*;
import org.javaboy.ai.service.IAiService;
import org.javaboy.ai.service.IInterviewRecordsService;
import org.javaboy.ai.service.IModelsService;
import org.javaboy.common.config.AiProperties;
import org.javaboy.common.constant.AiConstants;
import org.javaboy.common.core.redis.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@EnableConfigurationProperties(AiProperties.class)
public class AiServiceImpl implements IAiService {
    @Autowired
    RedisCache redisCache;
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    AiProperties aiProperties;
    @Autowired
    IModelsService modelsService;
    @Autowired
    IInterviewRecordsService interviewRecordsService;

    /**
     * 服务端是支持多轮对话的
     *
     * @param mpRequest
     * @param openid
     * @return
     */
    @Override
    public MpAnswer chat(MpRequest mpRequest, String openid) {
        //1. 先去进行 AI 大模型的认证
        String accessToken = getAccessToken();
        //2. 根据小程序传递的模型名称，去查询这个模型的信息
        Models models = getModels(mpRequest.getModelName());
        //3. 读取当前会话之前的聊天数据
        List<AiChatMessage> messages = loadChatMessages(mpRequest.getSessionId());
        //4. 构建请求参数
        AiChatMessage message = new AiChatMessage();
        message.setRole(AiConstants.MESSAGE_ROLE_USER);
        if (mpRequest.getType().equals(AiConstants.MP_REQUEST_TYPE_Q)) {
            message.setContent(String.format(models.getQuestionPrompt(), mpRequest.getContent()));
        } else if (mpRequest.getType().equals(AiConstants.MP_REQUEST_TYPE_A)) {
            message.setContent(String.format(models.getAnswerPrompt(), mpRequest.getContent()));
        } else {
            throw new RuntimeException("请求类型错误，只能是 a 或者 q");
        }
        messages.add(message);
        AiRequestBody aiRequestBody = new AiRequestBody();
        aiRequestBody.setMessages(messages);
        aiRequestBody.setSystem(models.getRole());
        aiRequestBody.setUser_id(openid);
        //5. 发送请求
        AiResponseBody responseBody = restTemplate.postForObject(models.getUrl(), aiRequestBody, AiResponseBody.class, accessToken);
        AiChatMessage aiChatMessage = new AiChatMessage();
        aiChatMessage.setRole(AiConstants.MESSAGE_ROLE_ASSISTANT);
        aiChatMessage.setContent(responseBody.getResult());
        messages.add(aiChatMessage);
        cacheMessages(messages, mpRequest, openid);
        MpAnswer mpAnswer = new MpAnswer();
        mpAnswer.setType(AiConstants.MP_QUESTION_TYPE_CHOICE);
        mpAnswer.setContent(responseBody.getResult());
        return mpAnswer;
    }

    private void cacheMessages(List<AiChatMessage> messages, MpRequest mpRequest, String openid) {
        redisCache.setCacheList(AiConstants.AI_SESSION_PREFIX + mpRequest.getSessionId(), messages);
        interviewRecordsService.saveMessages(mpRequest, messages.subList(messages.size() - 2, messages.size()), openid);
    }

    private List<AiChatMessage> loadChatMessages(String sessionId) {
        List<AiChatMessage> cacheList = redisCache.getCacheList(AiConstants.AI_SESSION_PREFIX + sessionId);
        if (cacheList == null || cacheList.size() == 0) {
            cacheList = loadMessagesFromDb(sessionId);
            if (cacheList == null) {
                cacheList = new ArrayList<>();
            }
        }
        return cacheList;
    }

    private List<AiChatMessage> loadMessagesFromDb(String sessionId) {
        return interviewRecordsService.loadMessagesFromDb(sessionId);
    }

    private Models getModels(String modelName) {
        if (modelName == null || "".equals(modelName)) {
            modelName = AiConstants.DEFAULT_AI_MODEL;
        }
        //1. 先从缓存中获取模型信息
        Models models = redisCache.getCacheMapValue(AiConstants.AI_MODEL_NAMES, modelName);
        if (models == null) {
            LambdaQueryWrapper<Models> qw = new LambdaQueryWrapper<>();
            qw.eq(Models::getName, modelName);
            qw.eq(Models::getDelFlag, 1);
            models = modelsService.getOne(qw);
            if (models == null) {
                throw new RuntimeException("模型不存在");
            }
            redisCache.setCacheMapValue(AiConstants.AI_MODEL_NAMES, modelName, models);
        }
        return models;
    }

    private String getAccessToken() {
        //1. 先从缓存中获取 access_token
        String accessToken = redisCache.getCacheObject(AiConstants.AI_ACCESS_TOKEN_KEY);
        if (accessToken != null && accessToken.length() > 0) {
            return accessToken;
        }
        //2. 获取 access_token
        LinkedMultiValueMap params = new LinkedMultiValueMap();
        params.add("grant_type", aiProperties.getGrantType());
        params.add("client_id", aiProperties.getClientId());
        params.add("client_secret", aiProperties.getClientSecret());
        Map<String, Object> map = restTemplate.postForObject(aiProperties.getAccessTokenUrl(), params, Map.class);
        accessToken = (String) map.get("access_token");
        redisCache.setCacheObject(AiConstants.AI_ACCESS_TOKEN_KEY, accessToken, 29, TimeUnit.DAYS);
        return accessToken;
    }
}
